using System;

namespace TrueCode.DependencyManager.BuildActions.Injection
{
  public class CallMethodByReflection : IInject
  {
    #region IBuildAction Members
    public void Execute( IBuildSession context )
    {
      var methodsProvider = context.GetService< IMethodProvider >();
      if( methodsProvider != null )
      {
        foreach( var method in methodsProvider.GetMethodsOf( context.Instance.GetType() ) )
        {
          try
          {
            var parameterValueProvider = context.GetService< IParameterProvider >( method.Name );

            #region Assert that parameterValueProvider is not null
            if( parameterValueProvider == null )
            {
              var exception = new InvalidOperationException( "ParameterValueProvider does not registered." );
              exception.Data.Add( "Aim", context.SessionAim );
              throw exception;
            }
            #endregion

            method.Invoke( context.Instance, parameterValueProvider.GetValuesFor( context, method.GetParameters() ) );
          }
          catch( Exception exc )
          {
            var exception = new Exception( exc.Message, exc );
            exception.Data.Add( "Type", context.SessionAim.Type );
            exception.Data.Add( "Method", method );
            throw exception;
          }
        }
      }
    }
    #endregion

    #region Nested type: ServiceKey
    public class ServiceKey : IEquatable< ServiceKey >
    {
      public readonly SessionAim SessionAim;
      public readonly string MethodName;

      public ServiceKey( Type type, string methodName )
      {
        SessionAim = new SessionAim( type );
        MethodName = methodName;
      }

      #region Implementation of IEquatable<ServiceKey>
      public bool Equals( ServiceKey other )
      {
        return other != null && SessionAim.Equals( other.SessionAim ) && string.Equals( MethodName, other.MethodName );
      }
      #endregion

      public override bool Equals( object obj )
      {
        return Equals( obj as ServiceKey );
      }

      public override int GetHashCode()
      {
        return SessionAim.GetHashCode() ^ MethodName.GetHashCode();
      }
    }
    #endregion
  }
}